<!DOCTYPE html>
<html>
 
<head>
    <meta charset="UTF-8">
    <title>2048</title>
    <style>
        * {
            font-family: arial;
            /*	user-select: none;*/
            font-weight: bold;
        }
 
        .header {
            width: 480px;
            font-size: 40px;
            margin: 60px auto 5px auto;
        }
 
        #score01 {
            color: #F00;
        }
 
        #all {
            width: 480px;
            height: 480px;
            background-color: #bbada0;
            margin: 0 auto;
            border-radius: 20px;
        }
 
        .cell {
            width: 100px;
            height: 100px;
            background-color: #ccc0b3;
            ;
            border-radius: 10px;
            text-align: center;
            line-height: 100px;
            font-size: 40px;
            color: #fff;
            float: left;
            margin: 16px 0px 0px 16px;
 
        }
 
        .n2 {
            background-color: #eee3da;
            color: #776e65;
        }
 
        .n4 {
            background-color: #ede0c8;
            color: #776e65;
        }
 
        .n8 {
            background-color: #f2b179;
        }
 
        .n16 {
            background-color: #f59563;
        }
 
        .n32 {
            background-color: #f67c5f;
        }
 
        .n64 {
            background-color: #f65e3b;
        }
 
        .n128 {
            background-color: #edcf72;
        }
 
        .n256 {
            background-color: #edcc61;
        }
 
        .n512 {
            background-color: #9c0;
        }
 
        .n1024 {
            background-color: #33b5e5;
            font-size: 40px;
        }
 
        .n2048 {
            background-color: #09c;
            font-size: 40px;
        }
 
        .n4096 {
            background-color: #a6c;
            font-size: 40px;
        }
 
        .n8192 {
            background-color: #93c;
            font-size: 40px;
        }
 
        #gameover {
            position: absolute;
            background-color: rgba(0, 0, 0, 0.2);
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
            font-size: 40px;
            display: none;
        }
 
        #gameover p {
            background-color: #fff;
            width: 300px;
            height: 200px;
            border-radius: 10px;
            line-height: 66.66px;
            text-align: center;
            position: absolute;
            left: 50%;
            top: 50%;
            margin-left: -150px;
            margin-top: -150px;
        }
 
        #gameover p a {
            padding: 10px;
            text-decoration: none;
            background-color: #9f8d77;
            color: #fff;
            border-radius: 10px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <!--分数-->
    <p class="header">分数: <span id="score01"></span></p>
    <!--游戏部分-->
    <div id="all">
        <!--第一行-->
        <div class="cell" id="n00"></div>
        <div class="cell" id="n01"></div>
        <div class="cell" id="n02"></div>
        <div class="cell" id="n03"></div>
        <!--第二行-->
        <div class="cell" id="n10"></div>
        <div class="cell" id="n11"></div>
        <div class="cell" id="n12"></div>
        <div class="cell" id="n13"></div>
        <!--第三行-->
        <div class="cell" id="n20"></div>
        <div class="cell" id="n21"></div>
        <div class="cell" id="n22"></div>
        <div class="cell" id="n23"></div>
        <!--第四行-->
        <div class="cell" id="n30"></div>
        <div class="cell" id="n31"></div>
        <div class="cell" id="n32"></div>
        <div class="cell" id="n33"></div>
    </div>
    <!--弹框-->
    <div id="gameover">
        <p>
            游戏结束
            <br />
            分数:<span id="score02"></span>
            <br />
            <a onclick="typeonce()">再来一次</a>
        </p>
 
    </div>
    <script>
        //游戏环节
        var game = {
            data: [],  //定义一个数组存储
            score: 0,  //开始时分数为0
            gamerunning: 1,  //游戏开始时游戏状态为1
            gameover: 0,  //游戏结束时游戏状态为0
            status: 1,  //个人状态与游戏状态相对应，默认为1
            //游戏开始时还原所有
            start: function () {
                this.data = [
                    [0, 0, 0, 0],
                    [0, 0, 0, 0],
                    [0, 0, 0, 0],
                    [0, 0, 0, 0]
                ];
                this.score = 0;
                this.status = this.gamerunning;
                //随机生成两个数2或者4，方法调用5次
                this.randomNum();
                this.randomNum();
                this.randomNum();
                this.randomNum();
                this.randomNum();
                //更新视图
                this.dataView();
            },
            //随机赋值
            randomNum: function () {
                //循环获取是否方块存在空白位置
                while (true) {
                    //获取随机值
                    var r = Math.floor(Math.random() * 4);   //随机生成一个行
                    var c = Math.floor(Math.random() * 4);   //随机生成一个列
                    //判断 
                    if (this.data[r][c] == 0) {
                        //随机生成2或者4
                        var num = Math.random() > 0.2 ? 2 : 4;   //三元表达式
                        //赋值
                        this.data[r][c] = num;
                        //停止循环
                        break;
 
                    }
 
                }
            },
            //更新视图的方法
            dataView: function () {
                //		直接大循环
                for (var r = 0; r < 4; r++) {  //循环行
                    for (var c = 0; c < 4; c++) { //循环里面的每个单元格
                        //				找到对应的id的div
                        var div = document.getElementById("n" + r + c);  //字符串拼接
                        if (this.data[r][c] != 0) {
                            div.innerHTML = this.data[r][c]; //直接把数组中的数字展示到div中
                            div.className = "cell n" + this.data[r][c]; //设置对应div的样式
                        } else {
                            div.innerHTML = "";  //等于0的时候，div里面的内容直接置空
                            div.className = "cell";
                        }
                    }
                }
                //		更新分数
                document.getElementById("score01").innerHTML = this.score;
                //		判断游戏是否结束
                if (this.status == this.gameover) {  //游戏结束弹出框显示
                    document.getElementById("gameover").style.display = "block";
                    document.getElementById("score02").innerHTML = this.score;
                } else {   //游戏没有结束的时候弹出框一直隐藏
                    document.getElementById("gameover").style.display = "none";
                }
            },
            //	判断游戏是否结束的方法
            isgameove: function () {
                for (var r = 0; r < 4; r++) {
                    for (var c = 0; c < 4; c++) {
                        if (this.data[r][c] == 0) {  //有空白的时候
                            return false;
                        }
                        if (c < 3) {  //判断左右是否有相同，只需要判断到第三个格子即可
                            if (this.data[r][c] == this.data[r][c + 1]) {
                                return false;
                            }
                        }
                        if (r < 3) {
                            if (this.data[r][c] == this.data[r + 1][c]) {
                                return false;
                            }
                        }
                    }
                }
                return true;   //上面情况全都不符合，表示游戏已经GG了，返回一个true
            },
            //移动的方法
            //数字左移
            moveLeft: function () {
                //移动之前转化一次字符串
                var before = String(this.data);
                //循环每行数据
                for (var r = 0; r < 4; r++) {
                    //处理每一行的函数
                    this.moveLeftinRow(r);
                }
                //移动之后转换一次
                var after = String(this.data);
                //判断
                if (before != after) {
                    //随机生成两个数2或者4
                    this.randomNum();
                    if (this.isgameove()) { //如果游戏结束
                        //自己状态等于游戏结束状态
                        this.status = this.gameover;
                    }
                    //更新视图
                    this.dataView();
                }
 
            },
            //处理每一行的数据
            moveLeftinRow: function (r) {
                //循环获取后面的数据,最左边不用考虑
                for (var c = 0; c < 3; c++) {
                    //变量接收
                    var nextc = this.moveLeftNum(r, c);
                    //判断是否为-1，否则则为找到数字
                    if (nextc != -1) {
                        if (this.data[r][c] == 0) {  //如果当前的数等于0，则当前的数和找到的数进行比较
                            this.data[r][c] = this.data[r][nextc];
                            //找到的数清空变为0
                            this.data[r][nextc] = 0;
                            //再次从最左边的数进行循环
                            c--;
 
                        }
                        else if (this.data[r][c] == this.data[r][nextc]) {
                            //如果当前的数等于找到的数，则相加
                            this.data[r][c] *= 2;
                            //找到的数清空变为0
                            this.data[r][nextc] = 0;
                            //数字相加一次分数加
                            this.score += this.data[r][c];
 
                        }
                    } else {
                        //如果没有找到数，则退出循环
                        break;
                    }
                }
 
            },
            moveLeftNum: function (r, c) {	//	左移
                //循环获取后面的数据,最左边不用考虑
                for (var i = c + 1; i < 4; i++) {
                    //判断后面是否找到数字
                    if (this.data[r][i] != 0) {
                        //返回下标
                        return i;
                    }
                }
                //如果没有找到，返回
                return -1;
            },
            //移动的方法
            //数字右移
            moveRight: function () {
                //移动之前转化一次字符串
                var before = String(this.data);
                //循环每行数据
                for (var r = 0; r < 4; r++) {
                    //处理每一行的函数
                    this.moveRightinRow(r);
                }
                //移动之后转换一次
                var after = String(this.data);
                //判断
                if (before != after) {
                    //随机生成两个数2或者4
                    this.randomNum();
                    if (this.isgameove()) { //如果游戏结束
                        //自己状态等于游戏结束状态
                        this.status = this.gameover;
                    }
                    //更新视图
                    this.dataView();
                }
 
            },
            //处理每一行的数据
            moveRightinRow: function (r) {
                //循环获取前面的数据,最左边不用考虑
                for (var c = 3; c >= 0; c--) {
                    //变量接收
                    var nextc = this.moveRightNum(r, c);
                    //判断是否为-1，否则则为找到数字
                    if (nextc != -1) {
                        if (this.data[r][c] == 0) {  //如果当前的数等于0，则当前的数和找到的数进行比较
                            this.data[r][c] = this.data[r][nextc];
                            //找到的数清空变为0
                            this.data[r][nextc] = 0;
                            //再次从最右边的数进行循环
                            c++;
 
                        }
                        else if (this.data[r][c] == this.data[r][nextc]) {
                            //如果当前的数等于找到的数，则相加
                            this.data[r][c] *= 2;
                            //找到的数清空变为0
                            this.data[r][nextc] = 0;
                            //数字相加一次分数加
                            this.score += this.data[r][c];
 
                        }
                    } else {
                        //如果没有找到数，则退出循环
                        break;
                    }
                }
 
            },
            moveRightNum: function (r, c) {	//	左移
                //循环获取前面的数据,最右边不用考虑
                for (var i = c - 1; i >= 0; i--) {
                    //判断前面是否找到数字
                    if (this.data[r][i] != 0) {
                        //返回下标
                        return i;
                    }
                }
                //如果没有找到，返回
                return -1;
            },
            //移动的方法
            //数字上移
            moveUp: function () {
                //移动之前转化一次字符串
                var before = String(this.data);
                //循环每行数据
                for (var c = 0; c < 4; c++) {
                    //处理每一行的函数
                    this.moveUpinRow(c);
                }
                //移动之后转换一次
                var after = String(this.data);
                //判断
                if (before != after) {
                    //随机生成两个数2或者4
                    this.randomNum();
                    if (this.isgameove()) { //如果游戏结束
                        //自己状态等于游戏结束状态
                        this.status = this.gameover;
                    }
                    //更新视图
                    this.dataView();
                }
 
            },
            //处理每一行的数据
            moveUpinRow: function (c) {
                //循环获取前面的数据,最上面不用考虑
                for (var r = 0; r < 3; r++) {
                    //变量接收
                    var nextr = this.moveUpNum(r, c);
                    //判断是否为-1，否则则为找到数字
                    if (nextr != -1) {
                        if (this.data[r][c] == 0) {  //如果当前的数等于0，则当前的数和找到的数进行比较
                            this.data[r][c] = this.data[nextr][c];
                            //找到的数清空变为0
                            this.data[nextr][c] = 0;
                            //再次从最上面的数进行循环
                            r--;
 
                        }
                        else if (this.data[r][c] == this.data[nextr][c]) {
                            //如果当前的数等于找到的数，则相加
                            this.data[r][c] *= 2;
                            //找到的数清空变为0
                            this.data[nextr][c] = 0;
                            //数字相加一次分数加
                            this.score += this.data[r][c];
 
                        }
                    } else {
                        //如果没有找到数，则退出循环
                        break;
                    }
                }
 
            },
            moveUpNum: function (r, c) {	//	上移
                //循环获取上面的数据,最右边不用考虑
                for (var i = r + 1; i < 4; i++) {
                    //判断下面是否找到数字
                    if (this.data[i][c] != 0) {
                        //返回下标
                        return i;
                    }
                }
                //如果没有找到，返回
                return -1;
            },
            //移动的方法
            //数字下移
            moveDown: function () {
                //移动之前转化一次字符串
                var before = String(this.data);
                //循环每行数据
                for (var c = 0; c < 4; c++) {
                    //处理每一行的函数
                    this.moveDowninRow(c);
                }
                //移动之后转换一次
                var after = String(this.data);
                //判断
                if (before != after) {
                    //随机生成两个数2或者4
                    this.randomNum();
                    if (this.isgameove()) { //如果游戏结束
                        //自己状态等于游戏结束状态
                        this.status = this.gameover;
                    }
                    //更新视图
                    this.dataView();
                }
 
            },
            //处理每一行的数据
            moveDowninRow: function (c) {
                //循环获取前面的数据,最下面不用考虑
                for (var r = 3; r >= 0; r--) {
                    //变量接收
                    var nextr = this.moveDownNum(r, c);
                    //判断是否为-1，否则则为找到数字
                    if (nextr != -1) {
                        if (this.data[r][c] == 0) {  //如果当前的数等于0，则当前的数和找到的数进行比较
                            this.data[r][c] = this.data[nextr][c];
                            //找到的数清空变为0
                            this.data[nextr][c] = 0;
                            //再次从最下面的数进行循环
                            r++;
 
                        }
                        else if (this.data[r][c] == this.data[nextr][c]) {
                            //如果当前的数等于找到的数，则相加
                            this.data[r][c] *= 2;
                            //找到的数清空变为0
                            this.data[nextr][c] = 0;
                            //数字相加一次分数加
                            this.score += this.data[r][c];
 
                        }
                    } else {
                        //如果没有找到数，则退出循环
                        break;
                    }
                }
 
            },
            moveDownNum: function (r, c) {	//	下移
                //循环获取前面的数据,最下面不用考虑
                for (var i = r - 1; i >= 0; i--) {
                    //判断上面是否找到数字
                    if (this.data[i][c] != 0) {
                        //返回下标
                        return i;
                    }
                }
                //如果没有找到，返回
                return -1;
            }
 
        }
 
        //键盘按下时事件
        document.onkeydown = function () {
            //键盘上
            if (event.keyCode == 37) {   //键盘左
                console.log("左")
                //左移
                game.moveLeft();
            } else if (event.keyCode == 38) {   //键盘上
                console.log("上")
                //上移
                game.moveUp();
 
            } else if (event.keyCode == 39) {   //键盘右
                console.log("右")
                //右移
                game.moveRight();
            } else if (event.keyCode == 40) {   //键盘下
                console.log("下")
                //下移
                game.moveDown();
            }
 
        }
 
        //键盘按下时事件
        document.onkeydown = function () {
            //键盘上
            if (event.keyCode == 37) {   //键盘左
                console.log("左")
                //左移
                game.moveLeft();
            } else if (event.keyCode == 38) {   //键盘上
                console.log("上")
                //上移
                game.moveUp();
 
            } else if (event.keyCode == 39) {   //键盘右
                console.log("右")
                //右移
                game.moveRight();
            } else if (event.keyCode == 40) {   //键盘下
                console.log("下")
                //下移
                game.moveDown();
            }
 
        }
 
        //游戏开始时调用
        game.start();
        console.log(game.data)
        console.log(game.score)
 
        //点击再来一次
        function typeonce() {
            document.getElementById("gameover").style.display = "none";
            window.location.href = "2048.html";
        }
    </script>
</body>
 
</html>